package dovs.phases;

import dovs.*;
import dovs.analysis.*;
import dovs.node.*;

/** 
 * 	Compiler phase to calculate resource information,
 *	such as JVM signatures and local variable indices.
 */
public aspect Resources extends DepthFirstAdapter {
	/** The JVM signature of the method */
	private String AMethodDecl.signature;

	/** The JVM signature of the constructor */
	private String AConstructorDecl.signature;

	/** The JVM signature of the class or interface */
	private String PTypeDecl.signature;

	/** The JVM signature of the field */
	private String AFieldDecl.signature;

	/** The index of this local variable */
	public int ALocalDecl.index;

	/** Internal counter used to assign consecutive
	 *  indices to local variables
	 */
	private int next_local_index;

	/** Get the JVM signature of this type */
	public String PType.getSignature() {
		throw new InternalCompilerError("Unknown type in getSignature: " + getClass().getName());
	}

	public String AVoidType.getSignature() {
		return "V";
	}

	public String AByteType.getSignature() {
		return "B";
	}

	public String AShortType.getSignature() {
		return "S";
	}

	public String AIntType.getSignature() {
		return "I";
	}

	public String ACharType.getSignature() {
		return "C";
	}

	public String ABooleanType.getSignature() {
		return "Z";
	}

	public String ANamedType.getSignature() {
		return "L" + decl.getSignature() + ";";
	}

	public String AArrayType.getSignature() {
		return "[" + getType().getSignature();
	}

	public String ANullType.getSignature() {
		throw new InternalCompilerError("The null type has no signature");
	}

	/** Get the JVM signature of this class */
	public String PTypeDecl.getSignature() {
		if (signature == null) {
			signature = canonical_name.replace('.', '/');
		}
		return signature;
	}

	/** Get the JVM signature of this field */
	public String AFieldDecl.getSignature() {
		if (signature == null) {
			PTypeDecl typed = getAncestor(PTypeDecl.class);
			signature = typed.getSignature() + "/" + getName().getText();
		}
		return signature;
	}

	/** Get the JVM signature of this method */
	public String AMethodDecl.getSignature() {
		if (signature == null) {
			PTypeDecl typed = getAncestor(PTypeDecl.class);
			StringBuilder sb = new StringBuilder();
			sb.append(typed.getSignature());
			sb.append("/");
			sb.append(getName().getText());
			sb.append("(");
			for (ALocalDecl formal : getFormals()) {
				sb.append(formal.getType().getSignature());
			}
			sb.append(")");
			sb.append(getReturnType().getSignature());
			signature = sb.toString();
		}
		return signature;
	}

	/** Get the JVM signature of this constructor */
	public String AConstructorDecl.getSignature() {
		if (signature == null) {
			AClassTypeDecl classd = getAncestor(AClassTypeDecl.class);
			StringBuilder sb = new StringBuilder();
			sb.append(classd.getSignature());
			sb.append("/<init>(");
			for (ALocalDecl formal : getFormals()) {
				sb.append(formal.getType().getSignature());
			}
			sb.append(")V");
			signature = sb.toString();
		}
		return signature;
	}

	@Override
	public void inAMethodDecl(AMethodDecl method) {
		if (method.isStatic()) {
			next_local_index = 0;
		} else {
			next_local_index = 1;
		}
	}

	@Override @SuppressWarnings("unused") 
	public void inAConstructorDecl(AConstructorDecl method) {
		next_local_index = 1;
	}

	public @Override
	void inALocalDecl(ALocalDecl local) {
		// Assign an index to a formal or local variable
		// The formals are traversed first, so they are
		// assigned the lowest indices (as they should).
		local.index = next_local_index++;
	}


}
